package cn.demo.common.utils;


import cn.demo.common.core.redis.RedisCache;
import cn.demo.common.exception.ServiceException;
import cn.demo.common.utils.spring.SpringUtils;
import cn.demo.common.utils.uuid.IdUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.UUID;
import java.util.concurrent.Callable;

/**
 * 分布式锁方法
 */
@Slf4j
public class LockUtils {

    private static RedisCache redisService = SpringUtils.getBean(RedisCache.class);

    /**
     * 分布式锁通用执行
     *
     * @param key         锁的键
     * @param uniqueValue 标识唯一值
     * @param callable    有返回值的执行代码
     * @return 执行Callable任务的结果
     */
    public static <T> T lockFun(String key, String uniqueValue, Callable<T> callable) {
        String uuid = IdUtils.fastSimpleUUID();
        String lock = "lock:" + key + ":" + uniqueValue;
        try {
            if (redisService.lockWait(lock, uuid)) {
                try {
                    return callable.call(); // 执行Callable并返回结果
                } catch (ServiceException e) {
                    throw new ServiceException(e.getMessage());
                } catch (Exception e) {
                    log.error("执行Callable任务时发生异常", e);
                    throw new ServiceException(e.getMessage());
                }
            } else {
                log.error("分布式锁获取失败");
                throw new ServiceException("执行失败");
            }
        } finally {
            redisService.releaseLock(lock, uuid);
        }
    }

    /**
     * 分布式锁通用执行
     *
     * @param key         锁的键
     * @param uniqueValue 标识唯一值
     * @param runnable    执行代码
     */
    public static void lockFun(String key, String uniqueValue, Runnable runnable) {
        String uuid = IdUtils.fastSimpleUUID();
        String lock = "lock:" + key + ":" + uniqueValue;
        try {
            if (redisService.lockWait(lock, uuid)) {
                runnable.run();
            } else {
                log.error("分布式锁获取失败");
                throw new ServiceException("执行失败");
            }
        } finally {
            redisService.releaseLock(lock, uuid);
        }
    }


}
